package com.clss.emergencycall.module.webrtcController

import android.annotation.SuppressLint
import android.annotation.TargetApi
import android.content.Context
import android.os.Build
import android.os.Handler
import android.util.Log
import com.clss.emergencycall.EmergencyApplication
import com.clss.emergencycall.base.Constant
import com.clss.emergencycall.module.stompNew.Stomp
import com.clss.emergencycall.module.stompNew.StompClient
import com.clss.emergencycall.module.stompNew.dto.LifecycleEvent
import com.clss.emergencycall.tools.eventbus.EventBusHelper
import com.clss.emergencycall.tools.eventbus.EventBusHelper.NETWORK_IS_CONNECTED
import com.clss.emergencycall.utils.SpHelper
import com.clss.emergencycall.utils.Tools
import com.clss.webrtclibrary.KurentoSignActionType
import com.clss.webrtclibrary.KurentoSignallingBean
import com.clss.webrtclibrary.Lg
import com.clss.webrtclibrary.MediaInfoBean
import com.google.gson.Gson
import io.reactivex.Observable
import io.reactivex.Observer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import org.apache.commons.text.StringEscapeUtils
import org.json.JSONObject
import java.util.concurrent.TimeUnit

@TargetApi(Build.VERSION_CODES.LOLLIPOP)
class WebRtcSignController (
        context: Context,
        webRtcSignListener: WebRtcSignListener,
        mediaInfoBean: MediaInfoBean) {

    private val TAG = this::class.java.simpleName
    private val mNoResponseTimeLimit: Long = 1 * 1000
    private val XMPP = "xmpp"
    private val STOMP = "stomp"
    private val SIGNALING = "SIGNALING"
    private val ROOM = "room"
    private val PLAYER = "player"

    private var mStompClient : StompClient? = null
    private var mMediaInfoBean : MediaInfoBean? = null
    private var mWebRtcSignListener : WebRtcSignListener? = null
//    private var mXmppBinder : XmppService.XmppBinder? = null
    private val mGson = Gson()
    private var isStompConnected = false
    private var isStompLine = false
    private var mSignType = ROOM
    private var isStarted = false
    private var mPlayerId = ""
    private var mContext : Context? = null
    private val mHandler = Handler()
    private var isVideoReconnecting = false
    private var isVideoConnected = true
    private var mFirstSign : KurentoSignallingBean? = null
    private var mWaitingForSignAnswer = false
    private var mCheckNetworkTask : Disposable? = null
    private val mCheckRunable = Runnable {
        Lg.i(TAG, "---mCheckRunable===")
        if(mWaitingForSignAnswer && mFirstSign != null){
            Lg.i(TAG, "---丢失了Answer信令===")
            if (isStompLine){

            }else{
                Lg.i(TAG, "---mCheckRunable=startStomp==")
                isStompLine = true
                mWaitingForSignAnswer = false
//                mXmppBinder?.removeIncomingMessageListener(this)
                createStompConnection()
            }
        }
    }

    init {
        Lg.e(TAG, "---init===" + mediaInfoBean.id)
        mContext = context
        mWebRtcSignListener = webRtcSignListener
        mMediaInfoBean = mediaInfoBean
//        mMediaInfoBean?.signalingBean?.protocolFlag = XMPP
//        mXmppBinder = xmppBinder
        isStompLine = mMediaInfoBean?.signalingBean?.protocolFlag == STOMP
    }

    /** WebRtc可以开始工作了 */
    fun signLineStartWork(){
        Lg.i(TAG, "---signLineStartWork===")
        setConnectingState(true)
        EmergencyApplication.setIsVideoOnLine(true)
        if (isStompLine){
            createStompConnection()
        }else {
            startXmppSendSign()
        }
    }

    /** 关闭信道 */
    fun disconnectionSignLine(){
        mHandler.removeMessages(0)
        EmergencyApplication.setIsVideoOnLine(false)
        mStompClient?.disconnect()
        mStompClient = null
//        mXmppBinder?.removeIncomingMessageListener(this)
        stopCheckNetworkRunnable()
    }

    /** stomp传递信令的方法 */
    @SuppressLint("CheckResult")
    private fun createStompConnection(){
        Lg.i(TAG, "---createStompConnection===" + mMediaInfoBean.toString())
        val headerMap = mapOf(Constant.APP_TOKEN to SpHelper.getInstance().token)
        mStompClient = Stomp.over(
                mMediaInfoBean?.signalingBean?.stompHost, headerMap)
                //低端手机开视频后可能会因为卡顿，无法及时发送心跳，导致stomp断连，所以就设为0，不发心跳
                .withClientHeartbeat(0).withServerHeartbeat(10000)
        mStompClient?.connect()

        mStompClient?.topic("/queue/SIGNALING_" + SpHelper.getInstance().userId)
                ?.subscribeOn(Schedulers.io())
                ?.observeOn(AndroidSchedulers.mainThread())
                ?.subscribe { topicMessage ->
                    Lg.i(TAG, "---Received===" + topicMessage.payload)
                    //TODO 收到新的信令消息
                    val body = JSONObject(topicMessage.payload).get("body").toString()
                    hasRemoteSignMessage(body)
                }

        mStompClient?.lifecycle()
                ?.subscribeOn(Schedulers.io())
                ?.observeOn(AndroidSchedulers.mainThread())
                ?.subscribe { lifecycle ->
                    run {
                        when (lifecycle.type) {
                            LifecycleEvent.Type.OPENED -> {
                                Lg.i(TAG, "--lifecycle-OPENED=isNetIsConnected==" + isVideoConnected)
                                //连接开启
                                isStompConnected = true
                                if (mFirstSign == null) {
                                    mWebRtcSignListener?.signLineIsOpened(!isVideoConnected)
                                }else{
                                    hasLocalSignMessagge(mFirstSign!!)
                                }
                            }
                            LifecycleEvent.Type.CLOSED -> {
                                Lg.i(TAG, "--lifecycle-CLOSED===")
                                //连接关闭
                                isStompConnected = false
                                mWebRtcSignListener?.signLineIsClosed()
                            }
                            LifecycleEvent.Type.ERROR -> {
                                Lg.i(TAG, "--lifecycle-ERROR===")
                                //连接报错
                                netStatusError()
                            }
                            LifecycleEvent.Type.FAILED_SERVER_HEARTBEAT -> {
                                Lg.i(TAG, "--lifecycle-FAILED_SERVER_HEARTBEAT===")
                                //心跳不正常
                            }
                        }
                    }
                }
    }

    /** 收到了远端的信令 */
    fun hasRemoteSignMessage(remoteSign : String){
        Lg.i(TAG, "---hasRemoteSignMessage===" + remoteSign)
        setConnectingState(false)
        setVideoConnectedState(true)
        val unescapeJson = StringEscapeUtils.unescapeJson(remoteSign)
        val receiveMsg = mGson.fromJson(unescapeJson, KurentoSignallingBean::class.java)
        Lg.i(TAG, "---receiveMsg.room===" + receiveMsg.room + "---mMediaInfoBean?.id===" + mMediaInfoBean?.id)
        if (receiveMsg.id.equals(KurentoSignActionType.leaveRoomAnswer.name) ||
                receiveMsg.id.equals(KurentoSignActionType.joinRoomAnswer.name)){
            isStarted = true
        }
        if (receiveMsg.id.equals(KurentoSignActionType.createResponse.name)){
            isStarted = true
            mPlayerId = receiveMsg.player
        }
        if (mSignType.equals(ROOM)) {
            if (!mMediaInfoBean?.id.equals(receiveMsg.room)) {
                Lg.e(TAG, "---it's not current room===")
                return
            }
        }else if (mSignType.equals(PLAYER)){
            if (!mPlayerId.equals(receiveMsg.player)){
                Lg.e(TAG, "---it's not current Player===")
                return
            }
        }
        if (isStarted) {
            mWebRtcSignListener?.hasRemoteSignInfo(receiveMsg)
        }
        if(remoteSign.contains("joinRoomAnswer")
                || remoteSign.contains("createResponse")){
            Lg.i(TAG, "---this is first answer===")
            mWaitingForSignAnswer = false
            mFirstSign = null
        }
    }

    @SuppressLint("CheckResult")
    fun hasLocalSignMessagge(sign : KurentoSignallingBean) {
        Lg.i(TAG, "---hasLocalSignMessagge===" + sign.toString())
        if (sign.id.equals(KurentoSignActionType.create.name)) {
            mSignType = PLAYER
        }
        if (isStompLine) {
            mStompClient?.send(
                    "/app/signaling.$mSignType.${mMediaInfoBean?.signalingBean?.stompDestination}",
                    mGson.toJson(sign))
                    ?.subscribeOn(Schedulers.io())
                    ?.observeOn(Schedulers.io())
                    ?.subscribe({
                        Lg.i(TAG, "---发送成功===")
                    })
        } else {
//            mXmppBinder?.sendWebRtcSignMessage(
//                    mMediaInfoBean?.signalingBean?.xmppDestination,
//                    mGson.toJson(sign), (if (mSignType.equals(PLAYER)) "PLAYER" else "ROOM"))
        }
        //如果是房间的第一条信令，记录下来，如果到了设定的时间限制没有返回，则切换信道重新发送本条信令
        if (sign.id.equals("joinRoom") || sign.id.equals("create")) {
            if (!isStompLine) {
                mWaitingForSignAnswer = true
                mFirstSign = sign
                mHandler.postDelayed(mCheckRunable, mNoResponseTimeLimit)
                Lg.i(TAG, "---this is first sign===" + (mFirstSign == null))
            }
        }
    }

    /** xmpp通道传递信令的方法 */
    private fun startXmppSendSign(){
        Lg.i(TAG, "---startXmppSendSign=isNetIsConnected==" + isVideoConnected)
//        mXmppBinder?.addIncomingMessageListener(this)
        mWebRtcSignListener?.signLineIsOpened(!isVideoConnected)
    }

//    override fun newIncomingWebRtcSignMessage(webRtcSign: String) {
//        Lg.i(TAG, "---newIncomingWebRtcSignMessage===" + String)
//        hasRemoteSignMessage(webRtcSign)
//    }
//
//    override fun newIncomingMessage(from: EntityBareJid?, message: Message?, chat: Chat?) {
//
//    }
//
//    override fun queryChatMessageHistoryResult(userName: String?, msgHistoryList: MutableList<Forwarded>?) {
//
//    }

    fun netStatusError(){
        setConnectingState(false)
        mFirstSign = null
        startCheckNetworkRunnable()
    }

    private fun setConnectingState(connecting : Boolean){
        Lg.i(TAG, "---setConnectingState===$connecting")
        isVideoReconnecting = connecting
        if(!connecting){
            setVideoConnectedState(false)
        }
    }

    private fun setVideoConnectedState(connected: Boolean){
        Lg.i(TAG, "---setVideoConnectedState===$connected")
        isVideoConnected = connected
    }

    fun startCheckNetworkRunnable(){
        Lg.i(TAG, "---startCheckNetworkRunnable===")
        Observable.interval(1000, TimeUnit.MILLISECONDS)
                .observeOn(Schedulers.io())
                .subscribeOn(Schedulers.io())
                .subscribe(object : Observer<Long> {
                    override fun onComplete() {
                        Lg.i(TAG, "---onComplete===")
                    }

                    override fun onSubscribe(d: Disposable) {
                        Lg.i(TAG, "---onSubscribe===")
                        mCheckNetworkTask = d
                    }

                    override fun onNext(t: Long) {
                        Lg.i(TAG, "---onNext==$t=${Thread.currentThread().name}")
                        checkNetState()
                    }

                    override fun onError(e: Throwable) {
                        Lg.i(TAG, "---onError===")
                    }
                })
    }

    fun stopCheckNetworkRunnable(){
        mCheckNetworkTask?.let { it.dispose() }
    }

    fun checkNetState(){
        Lg.i(TAG, "---checkNetState===")
        if (Tools.pingNetConnectionState()){
            Lg.i(TAG, "---ping通了===")
            EventBusHelper.sendEventBusMsg(NETWORK_IS_CONNECTED)
            stopCheckNetworkRunnable()
//            mStompClient?.reconnect()
            signLineStartWork()
        }else{
            Lg.i(TAG, "---ping没通===")

        }
    }
}
